package com.rednote.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.rednote.common.UserContextHolder;
import com.rednote.entity.Admins;
import com.rednote.entity.Posts;
import com.rednote.entity.vo.PostCardVO;
import com.rednote.entity.vo.PostVO;
import com.rednote.mapper.AdminsMapper;
import com.rednote.mapper.PostsMapper;
import com.rednote.service.PostsService;
import com.rednote.service.RecommendationService;
import com.rednote.service.task.SimilarityMatrixTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class RecommendationServiceImpl implements RecommendationService {

    @Autowired
    private PostsService postService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PostsMapper postsMapper;

    @Autowired
    private SimilarityMatrixTask similarityMatrixTask;
    @Override
    public Page<Integer> getRelatedRecommendations(Integer postId, int page, int size) throws JsonProcessingException {
        if (page < 1) page = 1;
        if (size < 1) size = 5; // 默认5条

        // 1. 获取完整推荐列表（缓存或实时计算）
        List<Integer> similarPostIds = getSimilarPostsFromCache(postId);

        // 2. 过滤已浏览帖子（登录用户）
/*        Integer userId = UserContextHolder.getUserId();
        List<Integer> candidateIds;
        if (userId != null) {
            candidateIds = filterViewedPosts(userId, similarPostIds);
        } else {
            candidateIds = new ArrayList<>(similarPostIds);
        }*/
        List<Integer> candidateIds;
        candidateIds = new ArrayList<>(similarPostIds);

        // 3. 计算分页起始和结束下标
        int fromIndex = (page - 1) * size;
        int toIndex = Math.min(fromIndex + size, candidateIds.size());

        // 4. 若候选列表不足返回的页码数据，补充热门推荐
        if (toIndex > candidateIds.size()) {
            int needCount = toIndex - candidateIds.size();

            List<PostCardVO> hotPosts = postService.recommend(0, needCount);
            for (PostCardVO hotPost : hotPosts) {
                if (!candidateIds.contains(hotPost.getId())) {
                    candidateIds.add(hotPost.getId());
                }
            }

            toIndex = Math.min(fromIndex + size, candidateIds.size());
            if (fromIndex > toIndex) {
                fromIndex = toIndex;
            }
        }

        // 5. 取分页数据（帖子ID列表）
        List<Integer> pagePostIds = candidateIds.subList(fromIndex, toIndex);

        // 6. 构造分页对象，只放帖子ID列表
        Page<Integer> pageResult = new Page<>();
        pageResult.setCurrent(page);
        pageResult.setSize(size);
        pageResult.setTotal(candidateIds.size());
        pageResult.setRecords(pagePostIds);

        return pageResult;
    }

    // 获取完整推荐列表，缓存未命中时实时计算，返回完整列表（不分页）
    public List<Integer> getSimilarPostsFromCache(Integer postId) {
        String key = "item_sim:" + postId;
        List<String> similarIds = redisTemplate.opsForList().range(key, 0, -1);
        if (similarIds == null || similarIds.isEmpty()) {
            return calculateRealTimeSimilarity(postId);
        }
        return similarIds.stream()
                .map(Integer::parseInt)
                .collect(Collectors.toList());
    }

    // 过滤用户已浏览的帖子（位图过滤）
    public List<Integer> filterViewedPosts(Integer userId, List<Integer> postIds) {
        String key = "user:viewed:" + userId;
        ByteBuffer keyBuffer = ByteBuffer.wrap(key.getBytes(StandardCharsets.UTF_8));

        List<Boolean> results = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (Integer postId : postIds) {
                connection.stringCommands().getBit(keyBuffer.array(), postId.longValue());
            }
            return null;
        }).stream().map(result -> (Boolean) result).toList();

        List<Integer> filtered = new ArrayList<>();
        for (int i = 0; i < postIds.size(); i++) {
            if (Boolean.FALSE.equals(results.get(i))) {
                filtered.add(postIds.get(i));
            }
        }
        return filtered;
    }

    // 实时计算相似度（只计算内容相似度）
    @Override
    public List<Integer> calculateRealTimeSimilarity(Integer postId) {
        Posts currentPost = postsMapper.selectById(postId);
        if (currentPost == null || currentPost.getVideoUrl() == null || currentPost.getVideoUrl().isEmpty()) {
            return new ArrayList<>();
        }

        List<Posts> videoPosts = postsMapper.selectList(
                new QueryWrapper<Posts>()
                        .isNotNull("video_url")
                        .ne("post_id", postId)
        );

        Map<Integer, Double> similarityMap = new HashMap<>();
        for (Posts otherPost : videoPosts) {
            double contentScore = similarityMatrixTask.calculateContentSimilarity(currentPost, otherPost);
            similarityMap.put(otherPost.getPostId(), contentScore);
        }

        return similarityMap.entrySet().stream()
                .sorted(Map.Entry.<Integer, Double>comparingByValue().reversed())
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }
}
